package com.example.parallelTemplate.completionServiceImplement.appProcess;

import com.example.parallelTemplate.commons.dto.BannerDTO;
import com.example.parallelTemplate.commons.dto.BaseRspDTO;
import com.example.parallelTemplate.commons.dto.LabelDTO;
import com.example.parallelTemplate.commons.dto.UserInfoDTO;
import com.example.parallelTemplate.commons.factory.TaskStrategyFactory;
import com.example.parallelTemplate.commons.param.BannerParam;
import com.example.parallelTemplate.commons.param.LabelParam;
import com.example.parallelTemplate.commons.param.UserInfoParam;
import com.example.parallelTemplate.commons.req.AppInfoReq;
import com.example.parallelTemplate.commons.response.AppHeadInfoResponse;
import com.example.parallelTemplate.commons.service.IBannerService;
import com.example.parallelTemplate.commons.service.ILabelService;
import com.example.parallelTemplate.commons.service.IUserService;
import com.example.parallelTemplate.completionServiceImplement.command.BaseTaskCommand;
import com.example.parallelTemplate.completionServiceImplement.service.IParallelInvokeCommonService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Component
public class AppHeadInfoServiceImpl implements IAppHeadInfoService {

    @Resource
    private IUserService userService;

    @Resource
    private IBannerService bannerService;

    @Resource
    private ILabelService labelService;

    @Resource
    private IParallelInvokeCommonService parallelInvokeCommonService;

    @Resource
    private TaskStrategyFactory taskStrategyFactory;


    @Override
    public AppHeadInfoResponse queryAppHeadInfo(AppInfoReq req) {

        long beginTime = System.currentTimeMillis();
        System.out.println("开始查询app首页信息，开始时间：" + beginTime);
        UserInfoParam userInfoParam = buildUserParam(req);
        UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam);

        BannerParam bannerParam = buildBannerParam(req);
        BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam);

        LabelParam labelParam = buildLabelParam(req);
        LabelDTO labelDTO = labelService.queryLabelInfo(labelParam);

        System.out.println("结束查询app首页信息,总耗时：" + (System.currentTimeMillis() - beginTime));
        return buildResponse(userInfoDTO, bannerDTO, labelDTO);
    }

    public AppHeadInfoResponse parallelQueryAppHeadPageInfo(AppInfoReq req) {

        long beginTime = System.currentTimeMillis();
        System.out.println("开始并行查询app首页信息，开始时间：" + beginTime);

        ExecutorService executor = Executors.newFixedThreadPool(10);
        CompletionService<BaseRspDTO<Object>> baseDTOCompletionService = new ExecutorCompletionService<BaseRspDTO<Object>>(executor);

        //查询用户信息任务
        Callable<BaseRspDTO<Object>> userInfoDTOCallableTask = () -> {
            UserInfoParam userInfoParam = buildUserParam(req);
            UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam);
            BaseRspDTO<Object> userBaseRspDTO = new BaseRspDTO<Object>();
            userBaseRspDTO.setKey("userInfoDTO");
            userBaseRspDTO.setData(userInfoDTO);
            return userBaseRspDTO;
        };

        //banner信息任务
        Callable<BaseRspDTO<Object>> bannerDTOCallableTask = () -> {
            BannerParam bannerParam = buildBannerParam(req);
            BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam);
            BaseRspDTO<Object> bannerBaseRspDTO = new BaseRspDTO<Object>();
            bannerBaseRspDTO.setKey("bannerDTO");
            bannerBaseRspDTO.setData(bannerDTO);
            return bannerBaseRspDTO;
        };

        //label信息查询任务
        Callable<BaseRspDTO<Object>> labelDTODTOCallableTask = () -> {
            LabelParam labelParam = buildLabelParam(req);
            LabelDTO labelDTO = labelService.queryLabelInfo(labelParam);
            BaseRspDTO<Object> labelBaseRspDTO = new BaseRspDTO<Object>();
            labelBaseRspDTO.setKey("labelDTO");
            labelBaseRspDTO.setData(labelDTO);
            return labelBaseRspDTO;
        };

        //提交用户信息任务
        baseDTOCompletionService.submit(userInfoDTOCallableTask);
        //提交banner信息任务
        baseDTOCompletionService.submit(bannerDTOCallableTask);
        //提交label信息任务
        baseDTOCompletionService.submit(labelDTODTOCallableTask);

        UserInfoDTO userInfoDTO = null;
        BannerDTO bannerDTO = null;
        LabelDTO labelDTO = null;

        try {
            //因为提交了3个任务，所以获取结果次数是3
            for (int i = 0; i < 3; i++) {
                Future<BaseRspDTO<Object>> baseRspDTOFuture = baseDTOCompletionService.poll(1, TimeUnit.SECONDS);
                BaseRspDTO baseRspDTO = baseRspDTOFuture.get();
                if ("userInfoDTO".equals(baseRspDTO.getKey())) {
                    userInfoDTO = (UserInfoDTO) baseRspDTO.getData();
                } else if ("bannerDTO".equals(baseRspDTO.getKey())) {
                    bannerDTO = (BannerDTO) baseRspDTO.getData();
                } else if ("labelDTO".equals(baseRspDTO.getKey())) {
                    labelDTO = (LabelDTO) baseRspDTO.getData();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("结束并行查询app首页信息,总耗时：" + (System.currentTimeMillis() - beginTime));
        return buildResponse(userInfoDTO, bannerDTO, labelDTO);
    }

    @Override
    public AppHeadInfoResponse parallelQueryAppHeadPageInfo1(AppInfoReq req) {

        long beginTime = System.currentTimeMillis();
        System.out.println("开始并行查询app首页信息，开始时间：" + beginTime);
        //用户信息查询任务
        Callable<BaseRspDTO<Object>> userInfoDTOCallableTask = () -> {
            UserInfoParam userInfoParam = buildUserParam(req);
            UserInfoDTO userInfoDTO = userService.queryUserInfo(userInfoParam);
            BaseRspDTO<Object> userBaseRspDTO = new BaseRspDTO<Object>();
            userBaseRspDTO.setKey("userInfoDTO");
            userBaseRspDTO.setData(userInfoDTO);
            return userBaseRspDTO;
        };

        //banner信息查询任务
        Callable<BaseRspDTO<Object>> bannerDTOCallableTask = () -> {
            BannerParam bannerParam = buildBannerParam(req);
            BannerDTO bannerDTO = bannerService.queryBannerInfo(bannerParam);
            BaseRspDTO<Object> bannerBaseRspDTO = new BaseRspDTO<Object>();
            bannerBaseRspDTO.setKey("bannerDTO");
            bannerBaseRspDTO.setData(bannerDTO);
            return bannerBaseRspDTO;
        };

        //label信息查询任务
        Callable<BaseRspDTO<Object>> labelDTODTOCallableTask = () -> {
            LabelParam labelParam = buildLabelParam(req);
            LabelDTO labelDTO = labelService.queryLabelInfo(labelParam);
            BaseRspDTO<Object> labelBaseRspDTO = new BaseRspDTO<Object>();
            labelBaseRspDTO.setKey("labelDTO");
            labelBaseRspDTO.setData(labelDTO);
            return labelBaseRspDTO;
        };

        List<Callable<BaseRspDTO<Object>>> taskList = new ArrayList<>();
        taskList.add(userInfoDTOCallableTask);
        taskList.add(bannerDTOCallableTask);
        taskList.add(labelDTODTOCallableTask);
        ExecutorService executor = Executors.newFixedThreadPool(10);
        List<BaseRspDTO<Object>> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor);
        if (resultList == null || resultList.size() == 0) {
            return new AppHeadInfoResponse();
        }

        UserInfoDTO userInfoDTO = null;
        BannerDTO bannerDTO = null;
        LabelDTO labelDTO = null;

        //遍历结果
        for (int i = 0; i < resultList.size(); i++) {
            BaseRspDTO baseRspDTO = resultList.get(i);
            if ("userInfoDTO".equals(baseRspDTO.getKey())) {
                userInfoDTO = (UserInfoDTO) baseRspDTO.getData();
            } else if ("bannerDTO".equals(baseRspDTO.getKey())) {
                bannerDTO = (BannerDTO) baseRspDTO.getData();
            } else if ("labelDTO".equals(baseRspDTO.getKey())) {
                labelDTO = (LabelDTO) baseRspDTO.getData();
            }
        }

        System.out.println("结束并行查询app首页信息,总耗时：" + (System.currentTimeMillis() - beginTime));
        return buildResponse(userInfoDTO, bannerDTO, labelDTO);
    }

    @Override
    public AppHeadInfoResponse parallelQueryAppHeadPageInfo2(AppInfoReq req) {
        long beginTime = System.currentTimeMillis();
        System.out.println("开始并行查询app首页信息（最终版本），开始时间：" + beginTime);
        List<Callable<BaseRspDTO<Object>>> taskList = new ArrayList<>();
        //用户信息查询任务
        taskList.add(new BaseTaskCommand("userInfoDTO", req, taskStrategyFactory));
        //banner查询任务
        taskList.add(new BaseTaskCommand("bannerDTO", req, taskStrategyFactory));
        //标签查询任务
        taskList.add(new BaseTaskCommand("labelDTO", req, taskStrategyFactory));

        ExecutorService executor = Executors.newFixedThreadPool(10);
        List<BaseRspDTO<Object>> resultList = parallelInvokeCommonService.executeTask(taskList, 3, executor);

        if (resultList == null || resultList.size() == 0) {
            return new AppHeadInfoResponse();
        }

        UserInfoDTO userInfoDTO = null;
        BannerDTO bannerDTO = null;
        LabelDTO labelDTO = null;

        for (BaseRspDTO<Object> baseRspDTO : resultList) {
            if ("userInfoDTO".equals(baseRspDTO.getKey())) {
                userInfoDTO = (UserInfoDTO) baseRspDTO.getData();
            } else if ("bannerDTO".equals(baseRspDTO.getKey())) {
                bannerDTO = (BannerDTO) baseRspDTO.getData();
            } else if ("labelDTO".equals(baseRspDTO.getKey())) {
                labelDTO = (LabelDTO) baseRspDTO.getData();
            }
        }

        System.out.println("结束并行查询app首页信息（最终版本）,总耗时：" + (System.currentTimeMillis() - beginTime));
        return buildResponse(userInfoDTO, bannerDTO, labelDTO);
    }

    private AppHeadInfoResponse buildResponse(UserInfoDTO userInfoDTO, BannerDTO bannerDTO, LabelDTO labelDTO) {
        if (userInfoDTO != null) {
            System.out.println(userInfoDTO.getUserId());
        }

        if (bannerDTO != null) {
            System.out.println(bannerDTO.getBannerId());
        }

        if (labelDTO != null) {
            System.out.println(labelDTO.getLabelId());
        }

        return new AppHeadInfoResponse();
    }

    private UserInfoParam buildUserParam(AppInfoReq req) {
        return new UserInfoParam();
    }

    private BannerParam buildBannerParam(AppInfoReq req) {
        return new BannerParam();
    }


    private LabelParam buildLabelParam(AppInfoReq req) {
        return new LabelParam();
    }

}
